package com.yuandian.management.service.impl;


import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yuandian.bpm.common.core.util.R;
import com.yuandian.management.enums.AgentStatus;
import com.yuandian.management.enums.StatusEnum;
import com.yuandian.management.enums.WrongStatusEnum;
import com.yuandian.management.mapper.AgentStatusInfoMapper;
import com.yuandian.management.service.IAgentIpService;
import com.yuandian.management.service.IAgentStatusInfoService;
import com.yuandian.management.service.IAgentTableService;
import com.yuandian.management.utils.IpUtils;
import com.yuandian.management.vo.*;
import com.yuandian.utils.DateTool;
import com.yuandian.utils.PageDataInfo;
import com.yuandian.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * <p>
 * Agent状态信息表 服务实现类
 * </p>
 *
 * @author fucx
 * @since 2021-01-27
 */
@Slf4j
@Service
public class AgentStatusInfoServiceImpl extends ServiceImpl<AgentStatusInfoMapper, AgentStatusInfoPojo> implements IAgentStatusInfoService {
	@Autowired
    private AgentStatusInfoMapper agentStatusInfoMapper;

    @Autowired
    private IAgentIpService agentIpService;

    @Autowired
    private IAgentTableService agentTableService;

    /**
     * 保存agent状态信息
     * 
     * @param apdtos
     * @param request
     */
    @Override
    public void handleAgentStatusInfo(AgentStatusInfoDto[] apdtos, HttpServletRequest request) {
        if(apdtos != null) {
            log.info("接收到了 agent信息个数："+apdtos.length + " , 开始处理请求。");
        }
        
        List<AgentStatusInfoDb> dbList = new ArrayList<AgentStatusInfoDb>();
        String tableName = "";

        for (AgentStatusInfoDto apdto : apdtos) {
            try {
                if (StringUtils.isNotBlank(apdto.getAgentIp())) {
                    String probeIp = IpUtils.getIpAddr(request);
                    if (StringUtils.isNotBlank(probeIp)) {
                        apdto.setProbeIp(probeIp);
                    }

                    List<AgentInfo> list = apdto.getAgentInfo();
                    if (!CollectionUtils.isEmpty(list)) {
                        log.info("当前agent:"+apdto.getAgentIp()+"接收到了 agentInfo个数："+list.size());
                        
                        
                        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

                        
                        //20200724讨论新加一条规则，同一个agent，不同网口，如果agent重启了，那么所有的网口都标记为rebootFlag=1，
                        //重启状态置为1，但不一定是异常，因为还要判断阀值是不是超过，且标记重启agent.setWrongStatus(WrongStatusEnum.RebootCount.getValue());
                        int rebootFlag = 0;
                        int rebootWrongStatus = 0;
                        
                        int i = 1;
                        for (AgentInfo agent : list) {
                            
                            log.debug("当前 agentInfo信息："+agent.toString());
                            
                            AgentStatusInfoPojo asip = new AgentStatusInfoPojo();
                            // 把agent基本信息copy
                            BeanUtils.copyProperties(apdto, asip);

                            // 把AgentInfo复制
                            BeanUtils.copyProperties(agent, asip);

                            String lastLaunchTime = apdto.getLastLaunchTime();
                            if (StringUtils.isNotBlank(lastLaunchTime)) {
                                Date lastLaunchDate = sdf.parse(lastLaunchTime);
                                asip.setLastLaunchTime(lastLaunchDate);
                            }
                            String lastUpdateTime = apdto.getLastUpdateTime();
                            if (StringUtils.isNotBlank(lastUpdateTime)) {
                                Date lastUpdateDate = sdf.parse(lastUpdateTime);
                                asip.setLastUpdateTime(lastUpdateDate);
                            }

                            //同一个agent他们的采集时间是一样的
                            if (i == 1) {
                                // 根据最后更新时间插入对应的表
                                tableName = agentTableService.getTodayAgentTable(asip.getLastUpdateTime());
                            }

                            // 全部初始状态
                            asip.setRebootFlag(0);
                            asip.setAgentStatus(0);
                            asip.setWrongStatus(0);
                            asip.setCollectTopStatus(0);
                            asip.setWrongTopStatus(0);
                            asip.setStatus(0);
                            Date now = new Date();
                            String nowStr = sdf.format(now);
                            asip.setCreateTime(now);

                            asip.setUpdateBy("admin");
                            asip.setUpdateTime(now);

                            asip.setRemoveDiskPartition("");
                            asip.setAgentThreshold("");

                            // 先从全局的缓存里面根据ip获取agent，如果没有，说明该agent是新的
                            boolean isNewAgent = true;
                            // 由于别名是前端设置的，要从缓存里面取
                            Map<String, AgentIpPojo> agetnMap = AgentConfigManager.agentIpMap;
                            if (agetnMap != null && agetnMap.get(asip.getAgentIp()) != null) {
                                AgentIpPojo ipPojo = agetnMap.get(asip.getAgentIp());
                                asip.setAliasName(ipPojo.getAliasName());

                                // 如果从缓存里面发现该Agent被管理员在前端逻辑删除了，那么这里发现又有数据进来，那么激活它
                                if (ipPojo.getStatus() == StatusEnum.DELETE.getValue()) {
                                    // 这里只更新状态
                                    AgentIpPojo io = new AgentIpPojo();
                                    io.setAgentIp(ipPojo.getAgentIp());
                                    io.setStatus(StatusEnum.NORMAL.getValue());
                                    agentIpService.updateByIpSelective(io);
                                }

                                isNewAgent = false;
                            } else {
                                // 如果是新的agent保存到表里面
                                initAgent(asip);
                            }

                            // 判断异常
                            dealAgentStatusByWrong(asip);

                            // 如果不是新的agent才判断重启
                            if (!isNewAgent) {
                                if(rebootFlag == 1 && rebootWrongStatus == WrongStatusEnum.RebootCount.getValue()) {
                                    asip.setRebootFlag(StatusEnum.DELETE.getValue());
                                    asip.setAgentStatus(AgentStatus.WRONG.getValue());
                                    asip.setWrongStatus(WrongStatusEnum.RebootCount.getValue());
                                }else if(rebootFlag == 1){
                                    //不超阀值
                                    asip.setRebootFlag(StatusEnum.DELETE.getValue());
                                }else {
                                    dealAgentStatusByReboot(asip, tableName);
                                }
                            }
                            
                            //因为同一个agent重启时间是一样的，所以只要第一个判断是重启，而且是异常的，后面不同网口都是同样的标志
                            if(i == 1) {
                                rebootFlag = asip.getRebootFlag();
                                rebootWrongStatus = asip.getWrongStatus();
                            }
                           

                            // 触发断采统计
                            dealAgentStatusByBreakCollection(asip);

                            AgentStatusInfoDb db = new AgentStatusInfoDb();
                            BeanUtils.copyProperties(asip, db);

                            if (StringUtils.isNotBlank(lastLaunchTime)) {
                                db.setLastLaunchTimeStr(lastLaunchTime);
                            }
                            if (StringUtils.isNotBlank(lastUpdateTime)) {
                                db.setLastUpdateTimeStr(lastUpdateTime);
                            }
                            db.setCreateTimeStr(nowStr);
                            db.setUpdateTimeStr(nowStr);

                            dbList.add(db);
                            
                            //标志位加1
                            i++ ;
                        }
                    }
                } else {
                    log.error("agentIp为空，接口接收的agent信息：" + apdto.toString());
                }
            } catch (Exception e) {
                log.error("接口接收的agent信息：" + apdto.toString());
                log.error(StringUtils.exceptionStackToString(e));
            }
        }

        if (dbList.size() > 0) {

            Map map = new HashMap();
            map.put("tableName", tableName);
            map.put("list", dbList);
            agentStatusInfoMapper.insertAgentStatusInfoBatch(map);
        }
        
        if(apdtos != null) {
            log.info("批量处理入库个数："+ dbList.size() + " , 结束处理请求。");
        }
    }

    /**
     * 判断异常状态
     * 
     * @param agent
     */
    private void dealAgentStatusByWrong(AgentStatusInfoPojo agent) {
        Map<String, AgentThresholdPojo> map = AgentConfigManager.agentThresholdMap;
        if (map != null && map.get(AgentConfigManager.AGENT_COLLECTION_THRESHOLD) != null) {
            AgentThresholdPojo threshold = map.get(AgentConfigManager.AGENT_COLLECTION_THRESHOLD);

            StringBuffer sb = new StringBuffer();
            sb.append("重启次数(次/天):");
            sb.append(threshold.getRebootCount());
            sb.append(" , 丢包率(%):");
            sb.append(threshold.getLostRate());
            sb.append(" , CPU使用率(%):");
            sb.append(threshold.getCpuRate());
            sb.append(" , 内存使用率(%):");
            sb.append(threshold.getMemoryRate());
            sb.append(" , 磁盘使用率(%):");
            sb.append(threshold.getDiskRate());
            
            agent.setAgentThreshold(sb.toString());
            
            Map<String, AgentIpPojo> agetnMap = AgentConfigManager.agentIpMap;
            AgentIpPojo agentIp = agetnMap.get(agent.getAgentIp());
            if(agentIp != null && StringUtils.isNotBlank(agentIp.getRemoveDiskPartition())) {
                agent.setRemoveDiskPartition(agentIp.getRemoveDiskPartition());
            }
            
            // 接口传的值是乘以10000
            Integer cpuRate = threshold.getCpuRate() * 100;
            if (cpuRate <= agent.getCpuRate()) {
                agent.setAgentStatus(AgentStatus.WRONG.getValue());
                agent.setWrongStatus(WrongStatusEnum.CpuRate.getValue());
                return;
            }

            Integer memoryRate = threshold.getMemoryRate() * 100;
            if (memoryRate <= agent.getMemoryRate()) {
                agent.setAgentStatus(AgentStatus.WRONG.getValue());
                agent.setWrongStatus(WrongStatusEnum.MemoryRate.getValue());
                return;
            }

            // 流量为0，即分钟总抓包为020200706和张乐、庄林讨论，拿分钟总抓包总数判断流量为0
            /*20200727杨总监说去掉流量为0的判断if (agent.getMinuteCaptureCount() != null && 0 == agent.getMinuteCaptureCount().intValue()) {
                agent.setAgentStatus(AgentStatus.WRONG.getValue());
                agent.setWrongStatus(WrongStatusEnum.MinuteCaptureZero.getValue());
                return;
            }*/

            Integer lostRate = threshold.getLostRate();
            if (agent.getMinuteCaptureCount() != null && 0 != agent.getMinuteCaptureCount().intValue()
                    && agent.getMinuteCaptureLostCount() != null) {
                //20200820张乐确认   丢包率 = 分钟丢包数  / (分钟抓包数 + 分钟丢包数) 
                double minuteRate = agent.getMinuteCaptureLostCount().doubleValue() / (agent.getMinuteCaptureCount().doubleValue() + agent.getMinuteCaptureLostCount().doubleValue())
                        * 100;
                if (minuteRate >= lostRate.doubleValue()) {
                    agent.setAgentStatus(AgentStatus.WRONG.getValue());
                    agent.setWrongStatus(WrongStatusEnum.LostRate.getValue());
                    return;
                }
            }

            // 磁盘默认100，没有乘以10000
            Integer diskRate = threshold.getDiskRate();
            if (diskRate <= agent.getDiskRate()) {
                // 特殊逻辑，1、首先判断磁盘占用率大于等于阀值。2、判断管理员是否配置了过滤磁盘分区，如果都完全都匹配，那么不算异常，如果不完全匹配，那么还是算异常(即map还有数据)。
                // 比如：/bak=91%|/root=90%。
                if (agentIp != null && StringUtils.isNotBlank(agentIp.getRemoveDiskPartition())
                        && StringUtils.isNotBlank(agent.getAllDiskInfo())) {
                    String[] diskInfos = agent.getAllDiskInfo().split("\\|");
                    Map<String, Integer> diskMap = new HashMap<String, Integer>();
                    for (String disk : diskInfos) {
                        if (StringUtils.isEmpty(disk)) {
                            continue;
                        }
                        // 截取分区名
                        String partision = disk.substring(0, disk.indexOf("="));

                        // 截取占比
                        String rateStr = disk.substring(disk.indexOf("=") + 1, disk.indexOf("%"));
                        Integer rate = Integer.parseInt(rateStr);

                        // 判断大于阀值的才放到map里面
                        if (rate >= threshold.getDiskRate()) {
                            diskMap.put(partision, rate);
                        }
                    }

                    if (diskMap.size() > 0) {
                        // 从系统启动的缓存里面获取的AgentIpPojo得到过滤的分区
                        if (StringUtils.isNotBlank(agentIp.getRemoveDiskPartition())) {
                            String[] partitions = agentIp.getRemoveDiskPartition().split("\\|");
                            for (String ss : partitions) {
                                if (diskMap.get(ss) != null) {
                                    diskMap.remove(ss);
                                }
                            }
                        }
                    }

                    if (diskMap.size() > 0) {
                        agent.setAgentStatus(AgentStatus.WRONG.getValue());
                        agent.setWrongStatus(WrongStatusEnum.DiskRate.getValue());
                        return;
                    }
                } else {
                    // 如果没有配置过滤分区规则，那么超过阀值，直接是异常
                    agent.setAgentStatus(AgentStatus.WRONG.getValue());
                    agent.setWrongStatus(WrongStatusEnum.DiskRate.getValue());
                    return;
                }
            }
        }
    }

    /**
     * 判断重启(每天多少次) 判断：逻辑就是取之前的最后重启时间判断，当前入库的agent，最后重启时间大于历史agent的时间，就算是重启，小于等于都算正常
     * 
     * @param agent
     * @param tableName
     */
    private void dealAgentStatusByReboot(AgentStatusInfoPojo agent, String tableName) {
        Map<String, AgentIpPojo> agetnMap = AgentConfigManager.agentIpMap;
        AgentIpPojo agentIp = agetnMap.get(agent.getAgentIp());
        if (agentIp != null) {
            // 更新缓存中的计算机名
            agentIp.setHostName(agent.getHostName());
        }
        if (agentIp != null && agent.getLastLaunchTime().compareTo(agentIp.getLastLaunchTime()) > 0) {
            //只要时间大于就算一次重启
            agent.setRebootFlag(StatusEnum.DELETE.getValue());
            
            // 查询阀值，看配置是一天多少次，如果一天一次，那么只要重启就是异常
            boolean isRebootMuch = true;
            Map<String, AgentThresholdPojo> map = AgentConfigManager.agentThresholdMap;
            if (map != null && map.get(AgentConfigManager.AGENT_COLLECTION_THRESHOLD) != null) {
                AgentThresholdPojo threshold = map.get(AgentConfigManager.AGENT_COLLECTION_THRESHOLD);
                Integer rebootNum = threshold.getRebootCount();
                if (rebootNum > 1) {
                    Map condition = new HashMap();
                    condition.put("tableName", tableName);
                    condition.put("agentIp", "'" + agent.getAgentIp() + "'");
                    int count = agentStatusInfoMapper.countRebootNumByIp(condition);
                    isRebootMuch = (count+1) >= rebootNum ? true : false;
                }
            }

            if (isRebootMuch) {
                agent.setAgentStatus(AgentStatus.WRONG.getValue());
                agent.setWrongStatus(WrongStatusEnum.RebootCount.getValue());
            }

            // 回填最新的重启时间到缓存里面
            agentIp.setLastLaunchTime(agent.getLastLaunchTime());

            AgentIpPojo apo = new AgentIpPojo();
            apo.setAgentIp(agent.getAgentIp());
            apo.setHostName(agent.getHostName());
            apo.setLastLaunchTime(agent.getLastLaunchTime());
            apo.setUpdateTime(new Date());

            agentIpService.updateByIpSelective(apo);
        }
    }

    /**
     * 判断断采 需要增加算法判断1分钟内，某个agent是否断采。(由于探针可能部署多台，同时发送到配置系统，不能保证前后关系)
     * 需要写算法：初始化一个map，key为年月日时分，value为初始化的Set集合，把正常状态的agent_ip初始化到Set里面，
     * 接收到数据后，以探针给的“最后更新时间”来判断是哪个key，如果不存在，生成一个key并初始化Set，同时移除对应的agent_ip；
     * 如果已经存在，把对应的Set里面移除掉该对应的agent_ip。同时判断当前“最后更新时间”减去5分得到的时间，把这个时间之前的数据都统计入库到agent状态信息表。
     * 比如“最后更新时间”为2020-06-03 19:16:07 那么减去5分， 得到2020-06-03
     * 19:16:02，那么比这个时间早的都统计入库，同时在map里面移除掉(避免内存溢出)。
     * 
     * @param agent
     */
    private void dealAgentStatusByBreakCollection(AgentStatusInfoPojo agent) {
        ConcurrentHashMap<String, Set<String>> timeMap = AgentConfigManager.timeMap;
        Map<String, AgentThresholdPojo> map = AgentConfigManager.agentThresholdMap;
        // 默认5分钟间隔统计断采入库
        Integer collectMinute = 5;
        if (map != null && map.get(AgentConfigManager.AGENT_COLLECTION_THRESHOLD) != null) {
            AgentThresholdPojo threshold = map.get(AgentConfigManager.AGENT_COLLECTION_THRESHOLD);
            if (threshold.getCollectMinute() != null) {
                collectMinute = threshold.getCollectMinute();
            }
        }

        Date before = DateTool.getBeforeMinute(new Date(), collectMinute - 1);
        // 目前是1分钟一次采集频率，系统默认配置5分钟入库统计是否断采，那么为了避免临界值取阀值再减1，即新的数据4分钟前进来，那么不判断是否断采
        // 目前是5分钟一次触发统计入库，会清理timeMap，所以上面建议是减1，比如当前为55分钟，那么小于等于51分的都不判断了。
        if (agent.getLastUpdateTime().compareTo(before) <= 0) {
            return;
        }

        //防止agent 中断的数据采集不到
        Date date = new Date();
        Date lastUpdateTime = agent.getLastUpdateTime();
        while (lastUpdateTime.compareTo(date) < 1){
            String timeStr = DateTool.yyyyMMddHHmm(lastUpdateTime);
            if (!timeMap.containsKey(timeStr)) {
                Set<String> set = new CopyOnWriteArraySet<String>();
                set.addAll(AgentConfigManager.ipSet);
                timeMap.put(timeStr, set);
            }
            lastUpdateTime = DateTool.getAfterMinute(lastUpdateTime, 1);
        }

        if (timeMap.containsKey(agent.getFormatTime())){
            timeMap.get(agent.getFormatTime());
        }else {
            Set<String> set = new CopyOnWriteArraySet<String>();
            set.addAll(AgentConfigManager.ipSet);
            log.debug(agent.getAgentIp() + " -- " + agent.getFormatTime() + "--移除自己前的ipSet:" + set.toString());

            timeMap.put(agent.getFormatTime(), set);
            //删除其他key 包
        }
        timeMap.get(agent.getFormatTime()).remove(agent.getAgentIp());
        log.debug(agent.getAgentIp() + " -- " + agent.getFormatTime() + "--移除自己后的ipSet:" + timeMap.get(agent.getFormatTime()).toString());

        // 有没有找到都开始处理统计入库的操作，以当前时间间隔前5分钟
        Date beforeMinute = DateTool.getBeforeMinute(new Date(), collectMinute);
        String formateDate = DateTool.yyyyMMddHHmm(beforeMinute);
        if (timeMap.size() > 0) {
        	dealBreakCollectionToDb(timeMap, formateDate);
            // 触发断采，更新t_agent_ip
            log.info("断采数据统计入库，更新t_agent_ip");
            AgentIpPojo agentIpPojo = new AgentIpPojo();
            BeanUtils.copyProperties(agent, agentIpPojo);
            agentIpService.updateByIpSelective(agentIpPojo);
        }

    }


    /**
     * 只要有数据进来，就触发断采统计入库操作
     * 
     * @param timeMap
     * @param formateDate
     */
    private void dealBreakCollectionToDb(ConcurrentHashMap<String, Set<String>> timeMap, String formateDate) {
        try {
            Long formateDateNum = Long.valueOf(formateDate);
            for (Map.Entry<String, Set<String>> entry : timeMap.entrySet()) {
                String key = entry.getKey();
                Long keyNum = Long.valueOf(key);
                Set<String> set = entry.getValue();


                // map里面的时间比formateDate小的都入库
                if (keyNum < formateDateNum && !CollectionUtils.isEmpty(set)) {
                    List<AgentStatusInfoDb> dbList = new ArrayList<AgentStatusInfoDb>();

                    log.debug(" -断采入库formatime：" + key + " ，入库的set:" + set.toString());

                    String time = key + "00";
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
                    Date newDate = sdf.parse(time);

                    SimpleDateFormat dbSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

                    for (String ip : set) {

                        Date now = new Date();
                        // 断采的数据只要ip、别名、入库时间、断采状态、主机名、formatTime，其他默认0
                        AgentStatusInfoDb collection = new AgentStatusInfoDb();
                        collection.setAgentIp(ip);
                        collection.setFormatTime(key);
                        // 由于别名是前端设置的，要从缓存里面取
                        Map<String, AgentIpPojo> agetnMap = AgentConfigManager.agentIpMap;
                        if (agetnMap != null && agetnMap.get(ip) != null) {
                            AgentIpPojo ipPojo = agetnMap.get(ip);
                            collection.setAliasName(ipPojo.getAliasName());
                            collection.setHostName(ipPojo.getHostName());
                        }
                        collection.setVersion("");
                        collection.setLastLaunchTime(newDate);
                        collection.setLastUpdateTime(newDate);

                        collection.setEthCount(0);
                        collection.setCapturePort("");
                        collection.setCaptureSpeed(0);
                        collection.setMinuteCaptureCount(0);
                        collection.setMinuteCaptureLostCount(0);
                        collection.setMinuteQueueLostCount(0);
                        collection.setCaptureCount(0L);
                        collection.setCaptureLostCount(0L);
                        collection.setQueueLostCount(0L);
                        collection.setSendSpeed(0);
                        collection.setCompressRate(0);
                        collection.setCpuRate(0);
                        collection.setMemoryRate(0);
                        collection.setDiskRate(0);
                        collection.setAllDiskInfo("");
                        collection.setRebootFlag(0);
                        collection.setAgentStatus(AgentStatus.BREAK_COLLECTION.getValue());
                        collection.setWrongStatus(0);
                        collection.setCollectTopStatus(0);
                        collection.setWrongTopStatus(0);
                        
                        collection.setRemoveDiskPartition("");
                        collection.setAgentThreshold("");

                        collection.setCreateTime(now);
                        collection.setUpdateBy("admin");
                        collection.setUpdateTime(now);
                        collection.setStatus(0);
                        collection.setRemarks("断采数据");

                        collection.setProbeIp("");

                        collection.setLastLaunchTimeStr(dbSdf.format(newDate));
                        collection.setLastUpdateTimeStr(dbSdf.format(newDate));
                        collection.setCreateTimeStr(dbSdf.format(now));
                        collection.setUpdateTimeStr(dbSdf.format(now));

                        dbList.add(collection);

                    }

                    if (dbList.size() > 0) {
                        // 需要根据key 计算是属于哪一天的表
                        SimpleDateFormat sdfD = new SimpleDateFormat("yyyyMMddHHmm");
                        Date keyDate = sdfD.parse(key);

                        String tableName = agentTableService.getTodayAgentTable(keyDate);

                        Map map = new HashMap();
                        map.put("tableName", tableName);
                        map.put("list", dbList);
                        agentStatusInfoMapper.insertAgentStatusInfoBatch(map);
                    }
                    // 已经处理入库的，清理掉
                    timeMap.remove(key);
                }
            }
        } catch (Exception e) {
            log.error(StringUtils.exceptionStackToString(e));
        }
    }

    private void initAgent(AgentStatusInfoPojo agent) {
        CopyOnWriteArraySet<String> ipSet = AgentConfigManager.ipSet;
        ipSet.add(agent.getAgentIp());

        AgentIpPojo ipPojo = new AgentIpPojo();
        // 把agent基本信息copy
        BeanUtils.copyProperties(agent, ipPojo);
        agentIpService.insertAgentIp(ipPojo);

        AgentConfigManager.agentIpMap.put(agent.getAgentIp(), ipPojo);
    }

    /**
     * 前端删除agent的时候查询十分钟该agent是否有数据，有就不能逻辑删除
     * 
     * @param map
     * @return
     */
    @Override
    public List<AgentStatusInfoVo> countTenMinuteGroupByIp(Map map) {
        return agentStatusInfoMapper.countTenMinuteGroupByIp(map);
    }

    /**
     * 统计断采个数、异常个数、正常个数
     * 
     * @return
     */
    @Override
    public List<AgentStatusInfoVo> countByAgentStatus() {
//        Date now = new Date();
//        String tableName = agentTableService.getTodayAgentTable(now);
        String zeroToday = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        Map map = new HashMap();
        map.put("tableName", "conf_agent_status_info");
        map.put("zeroToday", zeroToday);
        return agentStatusInfoMapper.countByAgentStatus(map);
    }

    /**
     * 查询当天该表的信息，按ip分组统计，参数是状态
     * 
     * @param ap
     * @return
     */
    @Override
    public R queryListGroupByIpAndAgentStatus(AgentStatusInfoParams ap) {
    	Page<AgentStatusInfoVo> page = new Page<>(ap.getPageNum(), ap.getPageSize());

        // 对前端传过来的ip处理
        if (StringUtils.isEmpty(ap.getAgentIp())) {
            ap.setAgentIp(null);
        }

//        Date now = new Date();
//        String tableName = agentTableService.getTodayAgentTable(now);
//        if (!querytableExsit(tableName)){
//            return Result.setFail(ApiResultCode.NO_EXIST_TABLE_CYCLE.getCode(), "所选时间表不存在!");
//        }
        String zeroToday = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        ap.setStartTime(zeroToday);
        Map map = new HashMap();
        map.put("tableName", "conf_agent_status_info");
        map.put("ap", ap);

        List<AgentStatusInfoVo> resultlist = agentStatusInfoMapper.queryListGroupByIpAndStatus(page,map);
        return R.ok(new PageDataInfo(page, resultlist));
    }

    private boolean querytableExsit(String tableName){
        int tableNum = agentStatusInfoMapper.queryTableExsit(tableName);
        return tableNum > 0 ? true : false;
    }

    /**
     * 查询当天的信息，按ip和状态查询
     * 
     * @param ap
     *            
     * @return
     */
    @Override
    public R queryListByIpAndAgentStatus(AgentStatusInfoParams ap) {
    	if(ap == null || StringUtils.isBlank(ap.getAgentIp()) || ap.getAgentStatus() == null) {
    		return R.failed(null, "agentIp和agentStatus不能为空");
    	}

        String zeroToday = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    	Page<AgentStatusInfoVo> page = new Page<>(ap.getPageNum(), ap.getPageSize());

        Date now = new Date();
        String tableName = agentTableService.getTodayAgentTable(now);
        Map map = new HashMap();
        map.put("tableName", tableName);
        map.put("ap", ap);
        map.put("zeroToday", zeroToday);
        List<AgentStatusInfoVo> resultlist = agentStatusInfoMapper.queryListByIpAndAgentStatus(page,map);
        return R.ok(new PageDataInfo(page, resultlist));
    }
    
    /**
     * 更新当天的不参加top展示的断采信息
     * 
     * @param agentIp
     * @return
     */
    @Override
    public int updateCollectTopStatusByIp(String agentIp) {

        Date now = new Date();
        String tableName = agentTableService.getTodayAgentTable(now);
        Map map = new HashMap();
        map.put("tableName", tableName);
        map.put("agentIp", "'" + agentIp + "'");

        return agentStatusInfoMapper.updateCollectTopStatusByIp(map);
    }

    /**
     * 前端操作，根据ip过滤掉当前的异常top排名
     * 
     * @param agentIp
     * @return
     */
    @Override
    public int updateWrongTopStatusByIp(String agentIp) {
        Date now = new Date();
        String tableName = agentTableService.getTodayAgentTable(now);
        Map map = new HashMap();
        map.put("tableName", tableName);
        map.put("agentIp", "'" + agentIp + "'");
        return agentStatusInfoMapper.updateWrongTopStatusByIp(map);
    }

    /**
     * 前端获取最新的一个agent详情
     * 
     * @param ap
     */
    @Override
    public AgentStatusInfoVo getAgentDetail(AgentStatusInfoPojo ap) {
        Date now = new Date();
        String tableName = agentTableService.getTodayAgentTable(now);
        Map map = new HashMap();
        map.put("tableName", tableName);
        map.put("ap", ap);

        AgentStatusInfoVo vo = agentStatusInfoMapper.getAgentDetail(map);

        if (vo == null) {
            Calendar c = Calendar.getInstance();
            c.setTime(now);
            c.add(Calendar.DAY_OF_MONTH, -2);
            Date startTime = c.getTime();

            List<String> tableNames = agentTableService.getHistoryAgentTable(startTime, now);
            Map mapH = new HashMap();
            mapH.put("list", tableNames);
            mapH.put("ap", ap);

            vo = agentStatusInfoMapper.getAgentDetailByHistory(mapH);
        }

        return vo;
    }

    

    /**
     * 根据ip获取该ip历史启动时间
     * 
     * @param agentIp
     */
    @Override
    public List<AgentStatusInfoVo> rebootHistoryTime(String agentIp) {
        AgentStatusInfoPojo ap = new AgentStatusInfoPojo();

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date now = new Date();
        Date end = now;

        Calendar c = Calendar.getInstance();
        c.setTime(now);
        c.add(Calendar.DAY_OF_MONTH, -2);
        Date startTime = c.getTime();

        List<String> tableNames = agentTableService.getHistoryAgentTable(startTime, end);
        Map map = new HashMap();
        map.put("list", tableNames);
        map.put("agentIp", agentIp);

        List<AgentStatusInfoVo> list = agentStatusInfoMapper.rebootHistoryTime(map);

        return list;
    }

    /**
     * 获取探针部署ip
     * 
     * @param moduleName
     * @return
     */
    @Override
    public List<String> getModuleManagement(String moduleName) {
        return agentStatusInfoMapper.getModuleManagement(moduleName);
    }

    /**
     * 统计agent状态个数
     * 
     * @return
     */
	@Override
	public R getAgentCount() {
        AgentStatusInfoVo vo = new AgentStatusInfoVo();
        int agentIpCount = agentIpService.countNormalAgentIp();
        vo.setAgentIpCount(agentIpCount);

        List<AgentStatusInfoVo> list = countByAgentStatus();
        if (!CollectionUtils.isEmpty(list)) {
            for (AgentStatusInfoVo statusVo : list) {
                if (statusVo.getAgentStatus() == AgentStatus.BREAK_COLLECTION.getValue()) {
                    vo.setBreakCollectCount(statusVo.getNormalCount());
                } else if (statusVo.getAgentStatus() == AgentStatus.WRONG.getValue()) {
                    vo.setWrongCount(statusVo.getNormalCount());
                } else {
                    vo.setNormalCount(statusVo.getNormalCount());
                }
            }
        }

        return R.ok(vo);
	}
    
    
	/**
     * 查询断采top数据
     * 
     * @return
     */
    @Override
    public R getBreakTop() {

//        Date now = new Date();
//        String tableName = agentTableService.getTodayAgentTable(now);
        String zeroToday = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        Map map = new HashMap();
        map.put("tableName", "conf_agent_status_info");
        map.put("zeroToday", zeroToday);

        List<AgentStatusInfoVo> list = agentStatusInfoMapper.getBreakTop(map);

        // y轴数组
        List<String> yAxis = new ArrayList<String>();
        List<Long> data = new ArrayList<Long>();

        if (list != null && list.size() > 0) {
            for (AgentStatusInfoVo agent : list) {
                String ip = agent.getAgentIp();
                yAxis.add(ip);
                if (agent.getBreakCollectCount() != null) {
                    data.add(agent.getBreakCollectCount().longValue());
                } else {
                    data.add(0L);
                }
            }
        }
        Map<String, Object> rMap = new HashMap<>(2);
        rMap.put("yAxis", yAxis);
        rMap.put("data", data);

        return R.ok(rMap);
    }

    /**
     * 查询异常top数据
     * 
     * @return
     */
    @Override
    public R getWrongTop() {
//        Date now = new Date();
//        String tableName = agentTableService.getTodayAgentTable(now);
//        判断表
        String zeroToday = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        Map map = new HashMap();
        map.put("tableName", "conf_agent_status_info");
        map.put("zeroToday", zeroToday);
        List<AgentStatusInfoVo> list = agentStatusInfoMapper.getWrongTop(map);
        // y轴数组
        List<String> yAxis = new ArrayList<String>();
        List<Long> data = new ArrayList<Long>();

        if (list != null && list.size() > 0) {
            for (AgentStatusInfoVo agent : list) {
                String ip = agent.getAgentIp();
                yAxis.add(ip);
                if (agent.getWrongCount() != null) {
                    data.add(agent.getWrongCount().longValue());
                } else {
                    data.add(0L);
                }
            }
        }

        Map<String, Object> rMap = new HashMap<>(2);
        rMap.put("yAxis", yAxis);
        rMap.put("data", data);

        return R.ok(rMap);
    }

    /**
     * 丢包率历史曲线图
     * 
     * @param params
     * @return
     */
	@Override
	public R lostHistoryLine(AgentStatusInfoParams params) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date now = new Date();
        Date start = now;
        Date end = now;
        try {
            start = sdf.parse(params.getStartTime());
            end = sdf.parse(params.getEndTime());
        } catch (ParseException e) {
            log.error("startTime:" + params.getStartTime() + " , endTime:" + params.getEndTime());
            log.error(e.getMessage(),e);
            return R.failed(null, "时间不能为空");
        }
        List<String> tableNames = agentTableService.getHistoryAgentTable(start, end);

        Map mybatisMap = new HashMap();
        mybatisMap.put("tableName", "conf_agent_status_info");
        mybatisMap.put("agentIp", params.getAgentIp());
        mybatisMap.put("startTime", params.getStartTime());
        mybatisMap.put("endTime", params.getEndTime());
//        if(tableNames == null || tableNames.size() <= 0) {
//        	 return Result.setSuccess(new LineChartVo());
//        }
        List<AgentStatusInfoVo> list = agentStatusInfoMapper.lostHistoryLine(mybatisMap);
        
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime startF = LocalDateTime.parse(params.getStartTime(), formatter);
        LocalDateTime endF = LocalDateTime.parse(params.getEndTime(), formatter);
        // 计算查询时间间隔
        Duration minutesDuration = Duration.between(startF, endF);
        long minutes = minutesDuration.toMinutes();


        SimpleDateFormat dyFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        //小于1天(SimpleDateFormat dyFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:00");)
        if(minutes <= 1440 ) {
        	dyFormat = new SimpleDateFormat("HH:mm");
        }
        // 时间x轴数组
        List<String> timeList = new ArrayList<String>();

        List<String> names = new ArrayList<String>();
        Map<String, List<String>> map = new LinkedHashMap();
        if (list != null && list.size() > 0) {
            for (AgentStatusInfoVo agent : list) {
                String name = "抓包口" + agent.getCapturePort() + "";
                
                String luTime = dyFormat.format(agent.getLastUpdateTime());
                
                //由于探针可能会在一分钟里面发两次，导致数据和时间标签不一致，那么如果同一分钟里面有两次，那么后面的值覆盖前面的
                boolean isExist = true;
                if (!timeList.contains(luTime)) {
                	isExist = false;
                    timeList.add(luTime);
                }

                Double rate = 0D;
                if (agent.getMinuteCaptureCount() != null && agent.getMinuteCaptureCount() != 0
                        && agent.getMinuteCaptureLostCount() != null) {
                    rate = agent.getMinuteCaptureLostCount().doubleValue() / (agent.getMinuteCaptureCount().doubleValue() + agent.getMinuteCaptureLostCount().doubleValue()) * 100;
                }

                List<String> timeVal = map.get(name);
                if (timeVal != null) {
                	//由于探针可能会在一分钟里面发两次，导致数据和时间标签不一致，那么如果同一分钟里面有两次，那么后面的值覆盖前面的
                	if(isExist && timeVal.size() == timeList.size()) {
                		timeVal.remove(timeVal.size() - 1);
                	}
                	timeVal.add(rate + "");
                } else {
                    names.add(name);
                    List<String> m = new ArrayList<String>();
                    m.add(rate + "");
                    map.put(name, m);
                }
            }
        }
        
        LineChartVo vo = new LineChartVo();
        vo.setTimeList(timeList);
        vo.setLegendList(names);
        List<SubLineChartVo> sbList = new ArrayList<SubLineChartVo>();
        for(String name : names) {
        	SubLineChartVo sbvo = new SubLineChartVo();
        	sbvo.setName(name);
        	sbvo.setData(map.get(name));
        	sbList.add(sbvo);
        }
        vo.setSubList(sbList);
        
        return R.ok(vo);
	}

	/**
     * 流量历史曲线图
     * 
     * @param params
     * @return
     */
	@Override
	public R speedHistoryLine(AgentStatusInfoParams params) {
//		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//        Date now = new Date();
//        Date start = now;
//        Date end = now;
//        try {
//            start = sdf.parse(params.getStartTime());
//            end = sdf.parse(params.getEndTime());
//        } catch (ParseException e) {
//            log.error("startTime:" + params.getStartTime() + " , endTime:" + params.getEndTime());
//            log.error(e.getMessage(),e);
//            return Result.setFail(ApiResultCode.AGENT_WARN_MESSAGE.getCode(), "时间不能为空");
//        }
//        List<String> tableNames = agentTableService.getHistoryAgentTable(start, end);
        Map mybatisMap = new HashMap();
        mybatisMap.put("tableName", "conf_agent_status_info");
        mybatisMap.put("agentIp", params.getAgentIp());
        mybatisMap.put("startTime", params.getStartTime());
        mybatisMap.put("endTime", params.getEndTime());
//        if(tableNames == null || tableNames.size() <= 0) {
//        	return Result.setSuccess(new LineChartVo());
//        }
        List<AgentStatusInfoVo> list = agentStatusInfoMapper.speedHistoryLine(mybatisMap);

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime startF = LocalDateTime.parse(params.getStartTime(), formatter);
        LocalDateTime endF = LocalDateTime.parse(params.getEndTime(), formatter);
        // 计算查询时间间隔
        Duration minutesDuration = Duration.between(startF, endF);
        long minutes = minutesDuration.toMinutes();


        SimpleDateFormat dyFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        //小于1天(SimpleDateFormat dyFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:00");)
        if(minutes <= 1440 ) {
        	dyFormat = new SimpleDateFormat("HH:mm");
        }
        // 时间x轴数组
        List<String> timeList = new ArrayList<String>();

        List<String> names = new ArrayList<String>();
        Map<String, List<String>> map = new LinkedHashMap();
        if (list != null && list.size() > 0) {
            for (AgentStatusInfoVo agent : list) {
                String name = "抓包口" + agent.getCapturePort() + "";
                String luTime = dyFormat.format(agent.getLastUpdateTime());
                //由于探针可能会在一分钟里面发两次，导致数据和时间标签不一致，那么如果同一分钟里面有两次，那么后面的值覆盖前面的
                boolean isExist = true;
                if (!timeList.contains(luTime)) {
                	isExist = false;
                    timeList.add(luTime);
                }

                Integer speed = agent.getCaptureSpeed();

                List<String> timeVal = map.get(name);
                if (timeVal != null) {
                	//由于探针可能会在一分钟里面发两次，导致数据和时间标签不一致，那么如果同一分钟里面有两次，那么后面的值覆盖前面的
                	if(isExist && timeVal.size() == timeList.size()) {
                		timeVal.remove(timeVal.size() - 1);
                	}
                	timeVal.add(speed + "");
                } else {
                    names.add(name);
                    List<String> m = new ArrayList<String>();
                    m.add(speed + "");
                    map.put(name, m);
                }
            }
        }
        LineChartVo vo = new LineChartVo();
        vo.setTimeList(timeList);
        vo.setLegendList(names);
        List<SubLineChartVo> sbList = new ArrayList<SubLineChartVo>();
        for(String name : names) {
        	SubLineChartVo sbvo = new SubLineChartVo();
        	sbvo.setName(name);
        	sbvo.setData(map.get(name));
        	sbList.add(sbvo);
        }
        vo.setSubList(sbList);
        
        return R.ok(vo);
	}
    
    
}
